The Challenge

Finance has the responsibility to forecast, plan and allocate resources in order to successfully deliver the best treatments to our patients.

  • The first challenge consist of deliver sales forecast for 2018 per cluster, per brand and per month.

  • The second challenge is to provide the optimal allocation of their resources for the year 2018.

Executive summary

  • An extensive exploratory data analysis has been carried out. It starts looking the aggregated levels of the data and, little by little, it focuses on more detailed aspects until it reaches the product level.

  • After analyzing the data, it can be concluded that a few products have most of the weight of the portfolio. Therefore, reducing the forecast error on this products will provide better savings to Novartis.

  • Different time series models have been evaluated with a holdout split. For every product, the best model has been selected to generate the final forecast. The overall MAPE is 15%.

  • To solve the allocation problem, multiple scenarios have been generated in order to find the best combination of investments for 2018.

Data preparation

All the data was provided in a single Excel file. This file contains for each brand of products two geographical levels (cluster and country), sales and investments in a monthly granularity.

Looking at the file, it seems a direct export from their CRM, time series data in wide format, with the totals of each quarter. This dataset needs some cleaning before starting to work with it.

Cluster Brand Group Country Function Jan 2012 Feb 2012 Mar 2012 ...8
Cluster 3 Brand Group 12 Country 19 Sales 1 1861.3 1995.9 1998.5 5855.8
Cluster 3 Brand Group 12 Country 19 Sales 2 1316.2 1450.2 1440.8 4207.3
Cluster 3 Brand Group 12 Country 19 Investment 1 -216.2 -238.2 -217.5 -671.8
Cluster 3 Brand Group 12 Country 19 Investment 2 -107.4 -14.2 -62.1 -183.8
Cluster 3 Brand Group 12 Country 19 Investment 4 0.0 0.0 0.0 0.0

The dimensions of the file are:

[1] 4228  123

Summary of the provided data:

  • Cluster (9): Highest level of geographical break down

  • Country (53): Lowest level of geographical break down

  • Brand Group (53): A pharmaceutical product

  • Function (8): Financial information related to:

    • Sales 1: Gross sales = volume sold * price
    • Sales 2: Net Sales = Sales 1 - Revenue deduction/ etc.
    • Investment 1-6: different investment types

Sales data is available from 2012 through 2017, while investments are available through 2018.

Cleaning up

As mentioned before, we are going to clean up the dataset with the following steps:

  • Remove totals of each quarter
  • Rename Brand Group to brand
  • Convert all headers to lower strings
df_raw <- df_raw %>% 
  rename(brand = `Brand Group`) %>% 
  select(-contains("...")) %>% 
  set_names(tolower)
cluster brand country function jan 2012 feb 2012 mar 2012 apr 2012
Cluster 3 Brand Group 12 Country 19 Sales 1 1861.3 1995.9 1998.5 2019.2
Cluster 3 Brand Group 12 Country 19 Sales 2 1316.2 1450.2 1440.8 1564.1
Cluster 3 Brand Group 12 Country 19 Investment 1 -216.2 -238.2 -217.5 -214.9
Cluster 3 Brand Group 12 Country 19 Investment 2 -107.4 -14.2 -62.1 -91.9

If we wanted to perform forecasts at the lowest possible level (cluster, country, brand) how many SKU we should have to forecast?

[1] "There are a total of 1184 SKU's to forecast"

Re-code brands

The forecast is only required for the following brands

data_wide <- df_raw %>% 
  mutate(
    brand = case_when(
      brand %in% "Brand Group 17" ~ "Brand Group 17",
      brand %in% "Brand Group 24" ~ "Brand Group 24",
      brand %in% "Brand Group 30" ~ "Brand Group 30",
      brand %in% "Brand Group 31" ~ "Brand Group 31",
      brand %in% "Brand Group 36" ~ "Brand Group 36",
      brand %in% "Brand Group 41" ~ "Brand Group 41",
      brand %in% paste("Brand Group", c(51, 73, 90)) ~ "Brand Group 51, 73, 90",
      brand %in% paste("Brand Group", c(96, 97)) ~ "Brand Group 96, 97",
      TRUE ~ "Others"
    )
)
cluster brand country function jan 2012 feb 2012 mar 2012 apr 2012
Cluster 3 Others Country 19 Sales 1 1861.3 1995.9 1998.5 2019.2
Cluster 3 Others Country 19 Sales 2 1316.2 1450.2 1440.8 1564.1
Cluster 3 Others Country 19 Investment 1 -216.2 -238.2 -217.5 -214.9
Cluster 3 Others Country 19 Investment 2 -107.4 -14.2 -62.1 -91.9
Cluster 3 Others Country 19 Investment 4 0.0 0.0 0.0 0.0
Cluster 3 Others Country 19 Investment 6 -57.0 -55.7 -64.7 -57.0

After this aggregations, we have:

[1] "There are 75 SKU's to forecast"

Reshape the data

Convert the data.frame to long format using pivot_longer and pivot_wider. Now, all the date columns have disappeared and all the dates appear in the date column. The data frame also contains sales and investments columns.

data_long <- data_wide %>% 
  mutate(
    `function` = `function` %>% str_to_lower() %>% str_replace(" ", "_") 
  ) %>% 
  pivot_longer(
    cols = -c(cluster, brand, country, `function`), 
    names_to = "date", 
    values_to = "value",
    names_transform = list(date = ~ parse_date_time(.x, orders = "my") ), 
  ) %>% 
  pivot_wider(
    id_cols = c(cluster, brand, country, date),
    names_from = `function`, 
    names_sort = TRUE,
    values_from = value,
    values_fn = sum
  ) %>% 
  select(cluster:date, starts_with("sales"), starts_with("investment"))
cluster brand country date sales_1 sales_2 investment_1 investment_2 investment_3 investment_4 investment_5 investment_6
Cluster 3 Others Country 19 2012-01-01 46952.6 38956.6 -216.2 -759.8 -569.5 0.0 -890.5 -126.8
Cluster 3 Others Country 19 2012-02-01 44180.0 34631.3 -239.5 -340.4 -199.3 0.0 -913.8 -135.9
Cluster 3 Others Country 19 2012-03-01 50465.6 39905.6 -216.2 -691.2 -1634.8 2.6 -1152.0 -137.2

Sales Visual Overview

We will start our visual exploration by investigating a number of time series plots on different aggregation levels. Then, we will continue exploring the relationship of the sales with their own past sales and the different investment.

All aggregate sales

  • The overall sales present an uptrend, specially after 2016.
  • There is a dip in sales in august.

Let’s break down the sales into geographies and brands.

Geography

There are two geographical levels: Cluster and Country.

Cluster

Highest level of geographical break down

[1] "Cluster 1"  "Cluster 2"  "Cluster 3"  "Cluster 4"  "Cluster 5"  "Cluster 7" 
[7] "Cluster 8"  "Cluster 9"  "Cluster 10"
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2

Form the image below we can see that how Cluster 10, Cluster 3, and Cluster 2 are the most important ones regarding sales, and Cluster 7 is the less important. It seems that there are two groups of clusters, one with the top three and other with the rest of the clusters.

Let’s see how the sales look like in the past. This time we want to explore visually if some clusters are more trending than others, are stationary or do present seasonal patterns.

  • Cluster 4 seems quite seasonal
  • Cluster 3 is the most trending one. Cluster 8 and Cluster 10 also have some trend.
  • Cluster 1, 5 and 7 are stable, do not increase/decrease over this period.

It is interesting to see how some clusters concentrate many countries while others are simply formed by one. However, despite these differences, the number of brands in all the countries is 8 or 9 except in Cluster 7 with 5 brands.

Another way of looking at the data is by it’s contribution to the portfolio. How much weight each country has? Almost 60% of the portfolio belongs to Clusters 10, Cluster 3 and Cluster 2.

  • Cluster 1 contains most countries, followed by Cluster 10 and Cluster 5 with 36, 6 and 4 countries respectively.

  • Clusters 2, 3, 4, 7 and 8 only have one country.

Cluster Number of countries Number of brands Weight
Cluster 1 36 9 0.07
Cluster 2 1 8 0.19
Cluster 3 1 8 0.20
Cluster 4 1 9 0.09
Cluster 5 4 9 0.05
Cluster 7 1 5 0.02
Cluster 8 1 9 0.11
Cluster 9 2 9 0.08
Cluster 10 6 9 0.20

Another way of looking at this data is with a tree map plot. As bigger the square it is more contribution to the portfolio they have, and as darker the shade it is, more countries in each cluster there are.

Country

Lowest level of geographical break down

[1] "Number of countries: 53"
 [1] "Country 10" "Country 11" "Country 12" "Country 13" "Country 14" "Country 15"
 [7] "Country 16" "Country 17" "Country 18" "Country 19"
  • Most sales come from few countries
  • There are many countries with very few sales
  • Countries like Country 25, 20 or 40 might have outliers. Before treat them as such, we should investigate if these values are due to increase/decrease in investments, marketing, etc.
  • Country 40 has high variability, as well as negative sales values.

All negative sales belong to cluster 1. There are 14 countries with negative values but without a doubt the most important one is Country 40 with 52 months with negative sales.

In case that we would like to see the 14 countries with negative sales

# Code to count cluster-countries with negative sales
by_country %>% 
  filter(value < 0) %>% 
  count(cluster, country, sort = TRUE)

We confirm that the two biggest countries are Country 19 and Country 17. The same shade of blue is maintained throughout the matrix, indicating that most countries have the same number of brands.

Brand Group

A Pharmaceutical product

[1] "Others"                 "Brand Group 17"         "Brand Group 24"        
[4] "Brand Group 31"         "Brand Group 36"         "Brand Group 41"        
[7] "Brand Group 51, 73, 90" "Brand Group 96, 97"     "Brand Group 30"        

Brand Others is the most significant at the sales level and the one with greatest dispersion. This can be for all the brands that it groups (see re-coding brands). On the other hand, Brand 41, Brand 30 and Brand 36 are the ones with less dispersion.

Below we can see that:

  • Seven out of nine brands are in an uptrend. Brand Group 41 and Others are the both in a downtrend with similar trend structure.
  • Brand Group 17 and Brand Group 24 present an exponential trend. Both brands starts between 2015 and 2016.
  • Brand Group 30, Brand Group 31 and Brand Group 51, 73, 90 are in an uptrend up to some point in time and then it becomes to remain almost flat for the rest of the time.
  • Brand Others has dips in august, as does total sales.

All levels

The forecast is required at the Cluster - Brand level. Recall that initially 1184 SKU’s have been provided and after the aggregation of the series we end up with 75 SKU’s.

In this section we will be able to answer question such as: Do the same brand follow the same pattern despite they do not belong to the same cluster?

all_levels <- data %>%
  group_by(cluster, brand, date) %>%
  summarise_at(vars(sales_1:investment_6), sum, na.rm = TRUE) %>%
  ungroup()

# Save this dataset for later use
write_rds(all_levels, file = file.path(path_data, "data_level_sku.rds"))

# Keep only with train data for better visualizations
all_levels <- all_levels %>%
  filter(date <= last_train)

With the following code we plot all the brands colored by cluster. However, we will only plot those cases that have remarkable features.

all_levels %>% 
  plot_time_series(x = date, y = sales_2, colour = cluster) +
  facet_wrap(~ brand, ncol = 3, scales = "fixed")

Some brands are more recent than others. Brand Group 17 and Brand Group 24 are examples of recent brands. where they began to be marketed from the beginning and end of 2015 respectively.

In the case of Brand Group 41 we can see a lot of variability within clusters, having in some clusters values below 10k and in others above 25k. On the other hand, it is interesting to see how the same brand behaves in a similar way in very cluster. This indicate us that this could be a good way to train our models.

We can also analyze the contribution of each product in the portfolio. More than 75% of the products have a weight less than or equal to 2%, while the other 25% have a weight bigger than 2%. We can also see how around 12% (9 products) of the products have a weights greater than 4%. This suggests that we should put more focus into some products than others.

Finally, we can visualize a tree map of the weights of each product. Notice how most important products belong to Others and Brand Group 41. Bigger squares and darker color means higher contribution to the portfolio.

Lagged sales

Many times the impact of the immediate past sales is not representative of what will come next. Imagine that we want to predict the temperature that we will have in august in an specific country. It would make sense to look at the past Augusts and see what is the average temperature rather than looking at the temperature of April or June.

On the x-axis is represented the lagged value of the sales and in the y-axis the real value. As closer the points are to the diagonal line better the correlation it is. Last year sales (12 months) seems a good predictor of current sales.

plot_data %>% 
  ggplot(aes(x = lag_value, y = sales_2)) +
  geom_point(shape = 21, colour = "black", fill = "orange", size = 3) +
  geom_smooth(method = lm, se = FALSE, colour = "black", lty = 2) +
  scale_x_continuous(
    labels = scales::label_number(suffix = "K", scale = 1e-3)
  ) +
  scale_y_continuous(
    labels = scales::label_number(suffix = "K", scale = 1e-3)
  ) +
  facet_wrap(~ lag_id, ncol = 3, scales = "fixed")

Investments

Investments

Overall investments

What is the most important investment type? In absolute terms, the most important investment are investment_1 and investment_2.

Sales vs Investments

To see the relationships between sales and investments, we can plot each time series against the others. These plots can be arranged in a scatterplot matrix, using the GGally package.

In this plot, mostly negative relationships with sales_2 are revealed, with the strongest relationships being with investment_1 and investment_5 and the weakest with investment_4.

  • Investments 1, 5 and 6 are highly correlated with sales_2
  • Investments 1, 5and 6 are highly correlated between them. Be cautious when modeling!
  • Investment 3 has an outlier on the left tail of the distribution.
  • Investment 4 does not have any effect over sales_2

Three out of six investments have a negative trend, therefore, it indicates that more and more has been invested. Recall that investments are negative and lower investments means more investing.

On the other hand, there is another group of investments that are stationary, that is, they are moving around their mean. In addition, investment_2 has annual seasonality, with spikes in august and September and valleys in December.

In January of 2016 there is an outlier in the investment_3.

Lagged Investments

Sometimes, the impact of a predictor that is included in a regression model will not be simple and immediate. For example, an advertising campaign may impact sales for some time beyond the end of the campaign, and sales in one month will depend on the advertising expenditure in each of the past few months.

LS0tDQp0aXRsZTogIkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMiDQphdXRob3I6ICJDYXJsb3MgRXNwZWxldGEiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMg0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICAgIHNtb290aF9zY3JvbGw6IG5vDQogICAgY29kZV9mb2xkaW5nOiBub25lDQogICAgdGhlbWU6IGNvc21vDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIGNzczogaW5jbHVkZS9jZW50ZXIuY3NzDQogICAgaW5jbHVkZXM6DQogICAgICBpbl9oZWFkZXI6IGluY2x1ZGUvZmF2aWNvbi5odG1sDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA5MA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCANCiAgZmlnLndpZHRoID0gNywgZmlnLmFsaWduID0gImNlbnRlciIsIA0KICBvdXQud2lkdGggPSAiOTUlIiwgZHBpID0gNzINCikNCmBgYA0KDQpgYGB7ciBsb2FkLWxpYnJhcmllcywgZWNobz1GQUxTRX0NCiMgTG9hZCBwYWNrYWdlcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQ0KbGlicmFyeShjcm9zc3RhbGspDQpsaWJyYXJ5KGNvbGxhcHNpYmxlVHJlZSkNCg0KIyBBdm9pZCBtZXNzYWdlIG9uIHN1bW1hcml6ZQ0Kb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpDQoNCiMgU2V0IGRlZmF1bHQgdGhlbWUgc2V0dGluZ3MNCnRoZW1lX3NldCgNCiAgdGhlbWVfbGlnaHQoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQopDQoNCiMgRW5nbGlzaA0KaW52aXNpYmxlKFN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICJFbmdsaXNoIikpDQoNCiMgRGVmaW5lIHBhdGhzIGRpcmVjdG9yaWVzDQpwYXRoX2RhdGEgPC0gIi4uL0RhdGEiDQoNCiMgRGVmaW5lIGxhc3QgdHJhaW4gZGF0ZQ0KbGFzdF90cmFpbiA8LSAiMjAxOC0wMS0wMSINCmBgYA0KDQpgYGB7ciBrbml0ci10YWJsZS1hdXh9DQp0b19odG1sIDwtIGZ1bmN0aW9uKGRmLCBkaWdpdHMgPSAyLCAuLi4pIHsNCiAga25pdHI6OmthYmxlKGRmLCBmb3JtYXQgPSAiaHRtbCIsIGRpZ2l0cykgJT4lIA0KICAgIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoDQogICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksDQogICAgICAuLi4NCiAgICApDQp9DQpgYGANCg0KYGBge3IgbG9nby1ub3ZhcnRpcywgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcuLi9JbWFnZXMvbG9nby1ub3ZhcnRpcy5wbmcnKQ0KYGBgDQoNCiMgVGhlIENoYWxsZW5nZSB7LnVubnVtYmVyZWR9DQoNCkZpbmFuY2UgaGFzIHRoZSByZXNwb25zaWJpbGl0eSB0byBmb3JlY2FzdCwgcGxhbiBhbmQgYWxsb2NhdGUgcmVzb3VyY2VzIGluIG9yZGVyIHRvDQpzdWNjZXNzZnVsbHkgZGVsaXZlciB0aGUgYmVzdCB0cmVhdG1lbnRzIHRvIG91ciBwYXRpZW50cy4NCg0KLSAgIFRoZSAqKmZpcnN0KiogY2hhbGxlbmdlIGNvbnNpc3Qgb2YgZGVsaXZlciBzYWxlcyBmb3JlY2FzdCBmb3IgMjAxOCBwZXIgY2x1c3RlciwgcGVyDQogICAgYnJhbmQgYW5kIHBlciBtb250aC4NCg0KLSAgIFRoZSAqKnNlY29uZCoqIGNoYWxsZW5nZSBpcyB0byBwcm92aWRlIHRoZSBvcHRpbWFsIGFsbG9jYXRpb24gb2YgdGhlaXIgcmVzb3VyY2VzDQogICAgZm9yIHRoZSB5ZWFyIDIwMTguDQoNCiMgRXhlY3V0aXZlIHN1bW1hcnkgey51bm51bWJlcmVkfQ0KDQoNCi0gQW4gZXh0ZW5zaXZlIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgaGFzIGJlZW4gY2FycmllZCBvdXQuIEl0IHN0YXJ0cyBsb29raW5nIHRoZSBhZ2dyZWdhdGVkIGxldmVscyBvZiB0aGUgZGF0YSBhbmQsIGxpdHRsZSBieSBsaXR0bGUsIGl0IGZvY3VzZXMgb24gbW9yZSBkZXRhaWxlZCBhc3BlY3RzIHVudGlsIGl0IHJlYWNoZXMgdGhlIHByb2R1Y3QgbGV2ZWwuDQoNCi0gQWZ0ZXIgYW5hbHl6aW5nIHRoZSBkYXRhLCBpdCBjYW4gYmUgY29uY2x1ZGVkIHRoYXQgYSBmZXcgcHJvZHVjdHMgaGF2ZSBtb3N0IG9mIHRoZSB3ZWlnaHQgb2YgdGhlIHBvcnRmb2xpby4gVGhlcmVmb3JlLCByZWR1Y2luZyB0aGUgZm9yZWNhc3QgZXJyb3Igb24gdGhpcyBwcm9kdWN0cyB3aWxsIHByb3ZpZGUgYmV0dGVyIHNhdmluZ3MgdG8gTm92YXJ0aXMuDQoNCi0gRGlmZmVyZW50IHRpbWUgc2VyaWVzIG1vZGVscyBoYXZlIGJlZW4gZXZhbHVhdGVkIHdpdGggYSBob2xkb3V0IHNwbGl0LiBGb3IgZXZlcnkgcHJvZHVjdCwgdGhlIGJlc3QgbW9kZWwgaGFzIGJlZW4gc2VsZWN0ZWQgdG8gZ2VuZXJhdGUgdGhlIGZpbmFsIGZvcmVjYXN0LiBUaGUgb3ZlcmFsbCBNQVBFIGlzIDE1JS4NCg0KLSBUbyBzb2x2ZSB0aGUgYWxsb2NhdGlvbiBwcm9ibGVtLCBtdWx0aXBsZSBzY2VuYXJpb3MgaGF2ZSBiZWVuIGdlbmVyYXRlZCBpbiBvcmRlciB0byBmaW5kIHRoZSBiZXN0IGNvbWJpbmF0aW9uIG9mIGludmVzdG1lbnRzIGZvciAyMDE4Lg0KDQojIERhdGEgcHJlcGFyYXRpb24NCg0KQWxsIHRoZSBkYXRhIHdhcyBwcm92aWRlZCBpbiBhIHNpbmdsZSBFeGNlbCBmaWxlLiBUaGlzIGZpbGUgY29udGFpbnMgZm9yIGVhY2ggYnJhbmQgb2YNCnByb2R1Y3RzIHR3byBnZW9ncmFwaGljYWwgbGV2ZWxzIChjbHVzdGVyIGFuZCBjb3VudHJ5KSwgc2FsZXMgYW5kIGludmVzdG1lbnRzIGluIGEgbW9udGhseQ0KZ3JhbnVsYXJpdHkuDQoNCkxvb2tpbmcgYXQgdGhlIGZpbGUsIGl0IHNlZW1zIGEgZGlyZWN0IGV4cG9ydCBmcm9tIHRoZWlyIENSTSwgdGltZSBzZXJpZXMgZGF0YSBpbiB3aWRlDQpmb3JtYXQsIHdpdGggdGhlIHRvdGFscyBvZiBlYWNoIHF1YXJ0ZXIuIFRoaXMgZGF0YXNldCBuZWVkcyBzb21lIGNsZWFuaW5nIGJlZm9yZSBzdGFydGluZw0KdG8gd29yayB3aXRoIGl0Lg0KDQpgYGB7ciBpbXBvcnQtZGF0YSwgZWNobz1GQUxTRX0NCiMgTG9hZCBleGNlbCBmaWxlDQpkZl9yYXcgPC0gDQogIHJlYWR4bDo6cmVhZF9leGNlbCgNCiAgICBwYXRoID0gZmlsZS5wYXRoKHBhdGhfZGF0YSwgIkRhdGFfTm92YXJ0aXNfRGF0YXRob24tUGFydGljaXBhbnRzLnhsc3giKSwgDQogICAgc2hlZXQgPSAiU2hlZXQxIiwNCiAgICBza2lwID0gMw0KICApDQoNCiMgU2hvdyBmaXJzdCByb3dzIGFuZCBjb2x1bW5zDQpoZWFkKGRmX3JhdywgNSkgJT4lIA0KICBzZWxlY3QoMTo4KSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpUaGUgZGltZW5zaW9ucyBvZiB0aGUgZmlsZSBhcmU6DQoNCmBgYHtyIGRpbWVuc2lvbnMtcmF3fQ0KZGltKGRmX3JhdykNCmBgYA0KDQpTdW1tYXJ5IG9mIHRoZSBwcm92aWRlZCBkYXRhOg0KDQotICAgKipDbHVzdGVyKiogKDkpOiBIaWdoZXN0IGxldmVsIG9mIGdlb2dyYXBoaWNhbCBicmVhayBkb3duDQoNCi0gICAqKkNvdW50cnkqKiAoNTMpOiBMb3dlc3QgbGV2ZWwgb2YgZ2VvZ3JhcGhpY2FsIGJyZWFrIGRvd24NCg0KLSAgICoqQnJhbmQgR3JvdXAqKiAoNTMpOiBBIHBoYXJtYWNldXRpY2FsIHByb2R1Y3QNCg0KLSAgICoqRnVuY3Rpb24qKiAoOCk6IEZpbmFuY2lhbCBpbmZvcm1hdGlvbiByZWxhdGVkIHRvOg0KDQogICAgLSAgICoqU2FsZXMgMSoqOiBHcm9zcyBzYWxlcyA9IHZvbHVtZSBzb2xkIFwqIHByaWNlDQogICAgLSAgICoqU2FsZXMgMioqOiBOZXQgU2FsZXMgPSAqU2FsZXMgMSogLSBSZXZlbnVlIGRlZHVjdGlvbi8gZXRjLg0KICAgIC0gICAqKkludmVzdG1lbnQgMS02Kio6IGRpZmZlcmVudCBpbnZlc3RtZW50IHR5cGVzDQoNClNhbGVzIGRhdGEgaXMgYXZhaWxhYmxlIGZyb20gMjAxMiB0aHJvdWdoIDIwMTcsIHdoaWxlIGludmVzdG1lbnRzIGFyZSBhdmFpbGFibGUgdGhyb3VnaA0KMjAxOC4NCg0KYGBge3IgY29sbGFwc2libGUtdHJlZS1wbG90fQ0KY29sbGFwc2libGVUcmVlKA0KICBkZiA9IGRmX3JhdyAlPiUgDQogICAgZGlzdGluY3QoQ2x1c3RlciwgQ291bnRyeSwgYEJyYW5kIEdyb3VwYCkgJT4lIA0KICAgIG11dGF0ZShDbHVzdGVyID0gZmN0X3JlbGV2ZWwoQ2x1c3RlciwgcGFzdGUoIkNsdXN0ZXIiLCBzZXEoMSwgMTApKSkpICU+JSANCiAgICBhcnJhbmdlKENsdXN0ZXIpLA0KICByb290ID0gIlRvdGFsIHNhbGVzIiwgDQogIGhpZXJhcmNoeSA9IGMoIkNsdXN0ZXIiLCAiQ291bnRyeSIsICJCcmFuZCBHcm91cCIpLA0KICBmaWxsQnlMZXZlbCA9IFRSVUUsIA0KICB6b29tYWJsZSA9IEZBTFNFLCBoZWlnaHQgPSA1MDAsIGZvbnRTaXplID0gMTQsIHdpZHRoID0gIjEwMCUiKQ0KYGBgDQoNCiMjIENsZWFuaW5nIHVwIHsjY2xlYW4taGVhZGVyc30NCg0KQXMgbWVudGlvbmVkIGJlZm9yZSwgd2UgYXJlIGdvaW5nIHRvIGNsZWFuIHVwIHRoZSBkYXRhc2V0IHdpdGggdGhlIGZvbGxvd2luZyBzdGVwczoNCg0KLSAgIFJlbW92ZSB0b3RhbHMgb2YgZWFjaCBxdWFydGVyDQotICAgUmVuYW1lIGBCcmFuZCBHcm91cGAgdG8gYGJyYW5kYA0KLSAgIENvbnZlcnQgYWxsIGhlYWRlcnMgdG8gbG93ZXIgc3RyaW5ncw0KDQpgYGB7ciBjbGVhbi1yYXctZGF0YS1mb3JtYXQsIGVjaG89VFJVRX0NCmRmX3JhdyA8LSBkZl9yYXcgJT4lIA0KICByZW5hbWUoYnJhbmQgPSBgQnJhbmQgR3JvdXBgKSAlPiUgDQogIHNlbGVjdCgtY29udGFpbnMoIi4uLiIpKSAlPiUgDQogIHNldF9uYW1lcyh0b2xvd2VyKQ0KYGBgDQoNCmBgYHtyfQ0KIyBTaG93IHNuYXBzaG90DQpoZWFkKGRmX3JhdywgNCkgJT4lIA0KICBzZWxlY3QoMTo4KSAlPiUgDQogIHRvX2h0bWwoZGlnaXRzID0gMSkNCmBgYA0KDQpJZiB3ZSB3YW50ZWQgdG8gcGVyZm9ybSBmb3JlY2FzdHMgYXQgdGhlIGxvd2VzdCBwb3NzaWJsZSBsZXZlbCAoY2x1c3RlciwgY291bnRyeSwgYnJhbmQpDQpob3cgbWFueSAqU0tVKiB3ZSBzaG91bGQgaGF2ZSB0byBmb3JlY2FzdD8NCg0KYGBge3IgbnVtLW9mLWZvcmVjYXN0LWF0LWxvdy1sZXZlbCwgZWNobz1GQUxTRX0NCm5fc2t1IDwtIGRmX3JhdyAlPiUgZGlzdGluY3QoY2x1c3RlciwgYnJhbmQsIGNvdW50cnkpICU+JSBucm93KCkNCnNwcmludGYoIlRoZXJlIGFyZSBhIHRvdGFsIG9mICVkIFNLVSdzIHRvIGZvcmVjYXN0Iiwgbl9za3UpDQpgYGANCg0KIyMgUmUtY29kZSBicmFuZHMgeyNyZWNvZGUtYnJhbmRzfQ0KDQpUaGUgZm9yZWNhc3QgaXMgb25seSByZXF1aXJlZCBmb3IgdGhlIGZvbGxvd2luZyBicmFuZHMNCg0KYGBge3IgcHJlcGFyaW5nLWdyb3VwcywgZWNobz1UUlVFfQ0KZGF0YV93aWRlIDwtIGRmX3JhdyAlPiUgDQogIG11dGF0ZSgNCiAgICBicmFuZCA9IGNhc2Vfd2hlbigNCiAgICAgIGJyYW5kICVpbiUgIkJyYW5kIEdyb3VwIDE3IiB+ICJCcmFuZCBHcm91cCAxNyIsDQogICAgICBicmFuZCAlaW4lICJCcmFuZCBHcm91cCAyNCIgfiAiQnJhbmQgR3JvdXAgMjQiLA0KICAgICAgYnJhbmQgJWluJSAiQnJhbmQgR3JvdXAgMzAiIH4gIkJyYW5kIEdyb3VwIDMwIiwNCiAgICAgIGJyYW5kICVpbiUgIkJyYW5kIEdyb3VwIDMxIiB+ICJCcmFuZCBHcm91cCAzMSIsDQogICAgICBicmFuZCAlaW4lICJCcmFuZCBHcm91cCAzNiIgfiAiQnJhbmQgR3JvdXAgMzYiLA0KICAgICAgYnJhbmQgJWluJSAiQnJhbmQgR3JvdXAgNDEiIH4gIkJyYW5kIEdyb3VwIDQxIiwNCiAgICAgIGJyYW5kICVpbiUgcGFzdGUoIkJyYW5kIEdyb3VwIiwgYyg1MSwgNzMsIDkwKSkgfiAiQnJhbmQgR3JvdXAgNTEsIDczLCA5MCIsDQogICAgICBicmFuZCAlaW4lIHBhc3RlKCJCcmFuZCBHcm91cCIsIGMoOTYsIDk3KSkgfiAiQnJhbmQgR3JvdXAgOTYsIDk3IiwNCiAgICAgIFRSVUUgfiAiT3RoZXJzIg0KICAgICkNCikNCmBgYA0KDQpgYGB7ciBzaG93LWRhdGEtcHJlcHJvY2Vzc2VkfQ0KaGVhZChkYXRhX3dpZGUsIDYpICU+JSANCiAgc2VsZWN0KDE6OCkgJT4lIA0KICB0b19odG1sKGRpZ2l0cyA9IDEpDQpgYGANCg0KQWZ0ZXIgdGhpcyBhZ2dyZWdhdGlvbnMsIHdlIGhhdmU6DQoNCmBgYHtyIG51bS1za3UtdG8tZm9yZWNhc3R9DQpuX3NrdSA8LSBkYXRhX3dpZGUgJT4lIGRpc3RpbmN0KGNsdXN0ZXIsIGJyYW5kKSAlPiUgbnJvdygpDQpzcHJpbnRmKCJUaGVyZSBhcmUgJWQgU0tVJ3MgdG8gZm9yZWNhc3QiLCBuX3NrdSkNCmBgYA0KDQojIyBSZXNoYXBlIHRoZSBkYXRhIHsjcmVzaGFwZS1kYXRhfQ0KDQpDb252ZXJ0IHRoZSBgZGF0YS5mcmFtZWAgdG8gbG9uZyBmb3JtYXQgdXNpbmcgYHBpdm90X2xvbmdlcmAgYW5kIGBwaXZvdF93aWRlcmAuIE5vdywgYWxsDQp0aGUgZGF0ZSBjb2x1bW5zIGhhdmUgZGlzYXBwZWFyZWQgYW5kIGFsbCB0aGUgZGF0ZXMgYXBwZWFyIGluIHRoZSBgZGF0ZWAgY29sdW1uLiBUaGUgZGF0YQ0KZnJhbWUgYWxzbyBjb250YWlucyBzYWxlcyBhbmQgaW52ZXN0bWVudHMgY29sdW1ucy4NCg0KYGBge3Igd2lkZS10by1sb25nLCBlY2hvPVRSVUV9DQpkYXRhX2xvbmcgPC0gZGF0YV93aWRlICU+JSANCiAgbXV0YXRlKA0KICAgIGBmdW5jdGlvbmAgPSBgZnVuY3Rpb25gICU+JSBzdHJfdG9fbG93ZXIoKSAlPiUgc3RyX3JlcGxhY2UoIiAiLCAiXyIpIA0KICApICU+JSANCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtYyhjbHVzdGVyLCBicmFuZCwgY291bnRyeSwgYGZ1bmN0aW9uYCksIA0KICAgIG5hbWVzX3RvID0gImRhdGUiLCANCiAgICB2YWx1ZXNfdG8gPSAidmFsdWUiLA0KICAgIG5hbWVzX3RyYW5zZm9ybSA9IGxpc3QoZGF0ZSA9IH4gcGFyc2VfZGF0ZV90aW1lKC54LCBvcmRlcnMgPSAibXkiKSApLCANCiAgKSAlPiUgDQogIHBpdm90X3dpZGVyKA0KICAgIGlkX2NvbHMgPSBjKGNsdXN0ZXIsIGJyYW5kLCBjb3VudHJ5LCBkYXRlKSwNCiAgICBuYW1lc19mcm9tID0gYGZ1bmN0aW9uYCwgDQogICAgbmFtZXNfc29ydCA9IFRSVUUsDQogICAgdmFsdWVzX2Zyb20gPSB2YWx1ZSwNCiAgICB2YWx1ZXNfZm4gPSBzdW0NCiAgKSAlPiUgDQogIHNlbGVjdChjbHVzdGVyOmRhdGUsIHN0YXJ0c193aXRoKCJzYWxlcyIpLCBzdGFydHNfd2l0aCgiaW52ZXN0bWVudCIpKQ0KYGBgDQoNCmBgYHtyIHJlb3JkZXItY2x1c3Rlci1sZXZlbHN9DQojIENsdXN0ZXIgYXMgZmFjdG9yIGZvciBiZXR0ZXIgcGxvdHMNCmNsdXN0ZXJfbHZscyA8LSBwYXN0ZSgiQ2x1c3RlciIsIHNlcSgxLCAxMCkpDQpkYXRhX2xvbmcgPC0gZGF0YV9sb25nICU+JSANCiAgbXV0YXRlKGNsdXN0ZXIgPSBmY3RfcmVsZXZlbChjbHVzdGVyLCBjbHVzdGVyX2x2bHMpKQ0KYGBgDQoNCmBgYHtyIHNob3ctZGF0YS1sb25nfQ0KaGVhZChkYXRhX2xvbmcsIDMpICU+JSANCiAgdG9faHRtbChkaWdpdHMgPSAxKSAlPiUgDQogIGthYmxlRXh0cmE6OnNjcm9sbF9ib3god2lkdGggPSAiMTAwJSIpDQpgYGANCg0KIyBTYWxlcyBWaXN1YWwgT3ZlcnZpZXcNCg0KV2Ugd2lsbCBzdGFydCBvdXIgdmlzdWFsIGV4cGxvcmF0aW9uIGJ5IGludmVzdGlnYXRpbmcgYSBudW1iZXIgb2YgdGltZSBzZXJpZXMgcGxvdHMgb24NCmRpZmZlcmVudCBhZ2dyZWdhdGlvbiBsZXZlbHMuIFRoZW4sIHdlIHdpbGwgY29udGludWUgZXhwbG9yaW5nIHRoZSByZWxhdGlvbnNoaXAgb2YgdGhlDQpzYWxlcyB3aXRoIHRoZWlyIG93biBwYXN0IHNhbGVzIGFuZCB0aGUgZGlmZmVyZW50IGludmVzdG1lbnQuDQoNCmBgYHtyIHBsb3QtYXV4LWZ1bmN0aW9uc30NCnBsb3RfdGltZV9zZXJpZXMgPC0gZnVuY3Rpb24oZGF0YSwgeCwgeSwgeV9zZWNvbmQsIC4uLiwgbGluZV9zaXplID0gMC41KSB7DQogIA0KICB4IDwtIHJsYW5nOjplbnF1byh4KQ0KICB5IDwtIHJsYW5nOjplbnF1byh5KQ0KICANCiAgcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSB7eyB4IH19LCB5ID0ge3sgeSB9fSwgLi4uKSkgKw0KICAgIGdlb21fbGluZShzaXplID0gbGluZV9zaXplKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoc3VmZml4ID0gIksiLCBzY2FsZSA9IDFlLTMpDQogICAgKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgY29sb3VyID0gTlVMTCkNCiAgDQogIGlmICghbWlzc2luZyh5X3NlY29uZCkpIHsNCiAgICB5X3NlY29uZCA8LSBybGFuZzo6ZW5xdW8oeV9zZWNvbmQpDQogICAgcCA8LSBwICsNCiAgICAgIGdlb21fbGluZShhZXMoeSA9IHt7IHlfc2Vjb25kIH19ICksIGNvbG9yID0gIm9yYW5nZSIsIA0KICAgICAgICAgICAgICAgIHNpemUgPSBsaW5lX3NpemUsIGFscGhhID0gMC41KQ0KICB9DQogIHANCn0NCmBgYA0KDQojIyBBbGwgYWdncmVnYXRlIHNhbGVzDQoNCi0gICBUaGUgb3ZlcmFsbCBzYWxlcyBwcmVzZW50IGFuIHVwdHJlbmQsIHNwZWNpYWxseSBhZnRlciAyMDE2Lg0KLSAgIFRoZXJlIGlzIGEgZGlwIGluIHNhbGVzIGluIGF1Z3VzdC4NCg0KYGBge3Igdml6LXRvdGFsLXNhbGVzfQ0KZGF0YSA8LSBkYXRhX2xvbmcNCg0KdG90YWxfc2FsZXMgPC0gZGF0YSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IGxhc3RfdHJhaW4pICU+JSANCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lIA0KICBzdW1tYXJpc2VfYXQodmFycyhzYWxlc18xOmludmVzdG1lbnRfNiksIHN1bSwgbmEucm0gPSBUUlVFKSAlPiUNCiAgdW5ncm91cCgpDQoNCiMgcGxvdF90aW1lX3Nlcmllcyh0b3RhbF9zYWxlcywgeCA9IGRhdGUsIHkgPSBzYWxlc18yKSArDQojICAgbGFicyh0aXRsZSA9ICJUb3RhbCBzYWxlcyIpDQoNCnBsb3RfbHkodG90YWxfc2FsZXMsIHggPSB+ZGF0ZSwgeSA9IH5zYWxlc18yLCBtb2RlID0gImxpbmVzIikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiVG90YWwgc2FsZXMiLA0KICAgIHhheGlzID0gbGlzdCgNCiAgICAgIHRpdGxlID0gTkFfY2hhcmFjdGVyXywNCiAgICAgIHR5cGUgPSAiZGF0ZSIsDQogICAgICByYW5nZXNlbGVjdG9yID0gbGlzdCgNCiAgICAgICAgYnV0dG9ucyA9IGxpc3QoDQogICAgICAgICAgbGlzdCgNCiAgICAgICAgICAgIGNvdW50ID0gNiwNCiAgICAgICAgICAgIGxhYmVsID0gIjYgbW8iLA0KICAgICAgICAgICAgc3RlcCA9ICJtb250aCIsDQogICAgICAgICAgICBzdGVwbW9kZSA9ICJiYWNrd2FyZCIpLA0KICAgICAgICAgIGxpc3QoDQogICAgICAgICAgICBjb3VudCA9IDEsDQogICAgICAgICAgICBsYWJlbCA9ICIxIHlyIiwNCiAgICAgICAgICAgIHN0ZXAgPSAieWVhciIsDQogICAgICAgICAgICBzdGVwbW9kZSA9ICJiYWNrd2FyZCIpLA0KICAgICAgICAgIGxpc3QoDQogICAgICAgICAgICBjb3VudCA9IDQsDQogICAgICAgICAgICBsYWJlbCA9ICI0IHlyIiwNCiAgICAgICAgICAgIHN0ZXAgPSAieWVhciIsDQogICAgICAgICAgICBzdGVwbW9kZSA9ICJiYWNrd2FyZCIpLA0KICAgICAgICAgIGxpc3Qoc3RlcCA9ICJhbGwiKSANCiAgICAgICAgKQ0KICAgICAgKQ0KICAgICksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gTkFfY2hhcmFjdGVyXyksDQogICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICJoIiksIA0KICAgIGF1dG9zaXplID0gRiwgd2lkdGggPSA3MDAjLCBoZWlnaHQgPSA0MDANCiAgKQ0KYGBgDQoNCkxldCdzIGJyZWFrIGRvd24gdGhlIHNhbGVzIGludG8gZ2VvZ3JhcGhpZXMgYW5kIGJyYW5kcy4NCg0KIyMgR2VvZ3JhcGh5DQoNClRoZXJlIGFyZSB0d28gZ2VvZ3JhcGhpY2FsIGxldmVsczogQ2x1c3RlciBhbmQgQ291bnRyeS4NCg0KIyMjIENsdXN0ZXINCg0KSGlnaGVzdCBsZXZlbCBvZiBnZW9ncmFwaGljYWwgYnJlYWsgZG93bg0KDQpgYGB7ciB1bmlxdWUtY2x1c3RlciwgZWNobz1GQUxTRX0NCmxldmVscyhkYXRhJGNsdXN0ZXIpDQpgYGANCg0KYGBge3IgYWdnLWJ5LWNsdXN0ZXJ9DQpwYWxldHRlIDwtICJTZXQzIiAjICAiU3BlY3RyYWwiDQoNCmJ5X2NsdXN0ZXIgPC0gZGF0YSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IGxhc3RfdHJhaW4pICU+JSANCiAgZ3JvdXBfYnkoY2x1c3RlciwgZGF0ZSkgJT4lIA0KICBzdW1tYXJpc2VfYXQodmFycyhzYWxlc18xOmludmVzdG1lbnRfNiksIHN1bSwgbmEucm0gPSBUUlVFKSAlPiUgDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCkZvcm0gdGhlIGltYWdlIGJlbG93IHdlIGNhbiBzZWUgdGhhdCBob3cgKkNsdXN0ZXIgMTAqLCAqQ2x1c3RlciAzKiwgYW5kICpDbHVzdGVyIDIqIGFyZQ0KdGhlIG1vc3QgaW1wb3J0YW50IG9uZXMgcmVnYXJkaW5nIHNhbGVzLCBhbmQgKkNsdXN0ZXIgNyogaXMgdGhlIGxlc3MgaW1wb3J0YW50LiBJdCBzZWVtcw0KdGhhdCB0aGVyZSBhcmUgdHdvIGdyb3VwcyBvZiBjbHVzdGVycywgb25lIHdpdGggdGhlIHRvcCB0aHJlZSBhbmQgb3RoZXIgd2l0aCB0aGUgcmVzdCBvZg0KdGhlIGNsdXN0ZXJzLg0KDQpgYGB7ciB2aXotYm94cGxvdC1ieS1jbHVzdGVyc30NCmJ5X2NsdXN0ZXIgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcihjbHVzdGVyLCBzYWxlc18yKSwgeSA9IHNhbGVzXzIsIGZpbGwgPSBjbHVzdGVyKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bnVtYmVyKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSBwYWxldHRlKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgY29sb3VyID0gTlVMTCwgZmlsbCA9IE5VTEwpDQpgYGANCg0KTGV0J3Mgc2VlIGhvdyB0aGUgc2FsZXMgbG9vayBsaWtlIGluIHRoZSBwYXN0LiBUaGlzIHRpbWUgd2Ugd2FudCB0byBleHBsb3JlIHZpc3VhbGx5IGlmDQpzb21lIGNsdXN0ZXJzIGFyZSBtb3JlIHRyZW5kaW5nIHRoYW4gb3RoZXJzLCBhcmUgc3RhdGlvbmFyeSBvciBkbyBwcmVzZW50IHNlYXNvbmFsDQpwYXR0ZXJucy4NCg0KLSAgICpDbHVzdGVyIDQqIHNlZW1zIHF1aXRlIHNlYXNvbmFsDQotICAgKkNsdXN0ZXIgMyogaXMgdGhlIG1vc3QgdHJlbmRpbmcgb25lLiAqQ2x1c3RlciA4KiBhbmQgKkNsdXN0ZXIgMTAqIGFsc28gaGF2ZSBzb21lDQogICAgdHJlbmQuDQotICAgKkNsdXN0ZXIgMSosICo1KiBhbmQgKjcqIGFyZSBzdGFibGUsIGRvIG5vdCBpbmNyZWFzZS9kZWNyZWFzZSBvdmVyIHRoaXMgcGVyaW9kLg0KDQpgYGB7ciB2aXotY2x1c3Rlcn0NCnBsb3RfdGltZV9zZXJpZXMoYnlfY2x1c3RlciwgeCA9IGRhdGUsIHkgPSBzYWxlc18yLCBjb2xvdXIgPSBjbHVzdGVyLCBsaW5lX3NpemUgPSAxKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gcGFsZXR0ZSkgKw0KICAjIGZhY2V0X3dyYXAofiBjbHVzdGVyLCBuY29sID0gMykgKw0KICAjIGxhYnModGl0bGUgPSAiQ2x1c3RlcnMiKQ0KICBsYWJzKHRpdGxlID0gTlVMTCkNCmBgYA0KDQpJdCBpcyBpbnRlcmVzdGluZyB0byBzZWUgaG93IHNvbWUgY2x1c3RlcnMgY29uY2VudHJhdGUgbWFueSBjb3VudHJpZXMgd2hpbGUgb3RoZXJzIGFyZQ0Kc2ltcGx5IGZvcm1lZCBieSBvbmUuIEhvd2V2ZXIsIGRlc3BpdGUgdGhlc2UgZGlmZmVyZW5jZXMsIHRoZSBudW1iZXIgb2YgYnJhbmRzIGluIGFsbCB0aGUNCmNvdW50cmllcyBpcyA4IG9yIDkgZXhjZXB0IGluICpDbHVzdGVyIDcqIHdpdGggNSBicmFuZHMuDQoNCkFub3RoZXIgd2F5IG9mIGxvb2tpbmcgYXQgdGhlIGRhdGEgaXMgYnkgaXQncyBjb250cmlidXRpb24gdG8gdGhlIHBvcnRmb2xpby4gSG93IG11Y2gNCndlaWdodCBlYWNoIGNvdW50cnkgaGFzPyBBbG1vc3QgNjAlIG9mIHRoZSBwb3J0Zm9saW8gYmVsb25ncyB0byAqQ2x1c3RlcnMgMTAqLCAqQ2x1c3RlciAzKg0KYW5kICpDbHVzdGVyIDIqLg0KDQotICAgKkNsdXN0ZXIgMSogY29udGFpbnMgbW9zdCBjb3VudHJpZXMsIGZvbGxvd2VkIGJ5ICpDbHVzdGVyIDEwKiBhbmQgKkNsdXN0ZXIgNSogd2l0aCAzNiwNCiAgICA2IGFuZCA0IGNvdW50cmllcyByZXNwZWN0aXZlbHkuDQoNCi0gICAqQ2x1c3RlcnMgMiosICozKiwgKjQqLCAqNyogYW5kICo4KiBvbmx5IGhhdmUgb25lIGNvdW50cnkuDQoNCmBgYHtyIHN1bW1hcnktc3RhdHMtYnktY2x1c3Rlcn0NCnRyZWVfbWFwIDwtIGRhdGEgJT4lIA0KICBncm91cF9ieShjbHVzdGVyKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBgTnVtYmVyIG9mIGNvdW50cmllc2AgPSBuX2Rpc3RpbmN0KGNvdW50cnkpLA0KICAgIGBOdW1iZXIgb2YgYnJhbmRzYCA9IG5fZGlzdGluY3QoYnJhbmQpLA0KICAgIFdlaWdodCA9IHN1bShzYWxlc18yLCBuYS5ybSA9IFRSVUUpDQogICkgJT4lDQogIG11dGF0ZShXZWlnaHQgPSBXZWlnaHQgLyBzdW0oV2VpZ2h0KSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICByZW5hbWUoQ2x1c3RlciA9IGNsdXN0ZXIpDQoNCnRyZWVfbWFwICU+JSANCiAgICB0b19odG1sKGRpZ2l0cyA9IDIsIGZ1bGxfd2lkdGggPSBGQUxTRSkNCmBgYA0KDQpBbm90aGVyIHdheSBvZiBsb29raW5nIGF0IHRoaXMgZGF0YSBpcyB3aXRoIGEgdHJlZSBtYXAgcGxvdC4gQXMgYmlnZ2VyIHRoZSBzcXVhcmUgaXQgaXMNCm1vcmUgY29udHJpYnV0aW9uIHRvIHRoZSBwb3J0Zm9saW8gdGhleSBoYXZlLCBhbmQgYXMgZGFya2VyIHRoZSBzaGFkZSBpdCBpcywgbW9yZQ0KY291bnRyaWVzIGluIGVhY2ggY2x1c3RlciB0aGVyZSBhcmUuDQoNCmBgYHtyIGNsdXN0ZXItdHJlZW1hcH0NCnBvaW50Rm9ybWF0dGVyIDwtIGhpZ2hjaGFydGVyOjpKUygiZnVuY3Rpb24oKXsNCiAgcmV0dXJuICc8Yj5XZWlnaHQ8L2I+OiAnICsgdGhpcy53X3RleHQgKyAnPGJyPicgKyAnPGI+Q291bnRyaWVzPC9iPjogJyArIA0KICB0aGlzWydOdW1iZXIgb2YgY291bnRyaWVzJ10NCn0iKQ0KDQp0cmVlX21hcCAlPiUgDQogIG11dGF0ZSh3X3RleHQgPSBzY2FsZXM6OnBlcmNlbnQoV2VpZ2h0LCBhY2N1cmFjeSA9IDAuMDEpKSAlPiUNCiAgaGNoYXJ0KCJ0cmVlbWFwIiwgDQogICAgICAgICBoY2Flcyh4ID0gQ2x1c3RlciwgdmFsdWUgPSBXZWlnaHQsIGNvbG9yID0gYE51bWJlciBvZiBjb3VudHJpZXNgKSwgDQogICAgICAgICBuYW1lID0gIldlaWdodCIpICU+JSANCiAgaGNfdG9vbHRpcChwb2ludEZvcm1hdHRlciA9IHBvaW50Rm9ybWF0dGVyKSAlPiUgDQogIGhjX2xlZ2VuZChhbGlnbiA9ICJyaWdodCIsIHZhbHVlRGVjaW1hbHMgPSAwKSANCmBgYA0KDQojIyMgQ291bnRyeQ0KDQpMb3dlc3QgbGV2ZWwgb2YgZ2VvZ3JhcGhpY2FsIGJyZWFrIGRvd24NCg0KYGBge3IgcHJpbnQtbnVtYmVyLW9mLWNvdW50cmllc30NCnNwcmludGYoIk51bWJlciBvZiBjb3VudHJpZXM6ICVkIiwgbl9kaXN0aW5jdChkYXRhJGNvdW50cnkpKQ0KYGBgDQoNCmBgYHtyIHVuaXF1ZS1jb3VudHJ5LCBlY2hvPUZBTFNFfQ0Kc29ydCh1bmlxdWUoZGF0YSRjb3VudHJ5KSlbMToxMF0NCmBgYA0KDQpgYGB7ciBhZ2ctYnktY291bnRyeX0NCmJ5X2NvdW50cnkgPC0gZGF0YSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IGxhc3RfdHJhaW4pICU+JSANCiAgZ3JvdXBfYnkoY2x1c3RlciwgY291bnRyeSwgZGF0ZSkgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0oc2FsZXNfMiwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIA0KICBtdXRhdGUoY2x1c3RlciA9IGZjdF9yZWxldmVsKGNsdXN0ZXIsIGNsdXN0ZXJfbHZscykpICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUgDQogIG11dGF0ZSgNCiAgICBjbHVzdGVyX2xhYmVsID0gc3ByaW50ZigiJXMgKG49JWQpIiwgY2x1c3Rlciwgbl9kaXN0aW5jdChjb3VudHJ5KSksDQogICAgY2x1c3Rlcl9sYWJlbCA9IGZjdF9yZWxldmVsKGNsdXN0ZXJfbGFiZWwsIGNsdXN0ZXJfbHZscykNCiAgKSAlPiUgDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCmBgYHtyIHRvcC1ib3R0b20tY291bnRyaWVzfQ0KIyBDYWxjdWxhdGUgdG9wIGFuZCBib3R0b20gY291bnRyaWVzIHRvIHBsb3QNCiMgdGhlbSBvcmRlcmVkIGluIGEgYm94cGxvdA0KdG90YWxfYnlfY291bnRyeSA8LSBieV9jb3VudHJ5ICU+JSANCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIA0KICBzdW1tYXJpc2UodG90YWxfc2FsZXMgPSBzdW0odmFsdWUsIG5hLnJtID0gVFJVRSkpDQoNCm4gPC0gMjUNCg0KIyBTZWxlY3QgdG9wIGBuYCAoMjUpDQp0b3Bfbl8gPC0gdG90YWxfYnlfY291bnRyeSAlPiUgDQogIHRvcF9uKHRvdGFsX3NhbGVzLCBuID0gbikgJT4lIA0KICBwdWxsKGNvdW50cnkpDQoNCiMgU2VsZWN0IGJvdHRvbSBgbmAgKDI1KQ0KYm90dG9tX25fIDwtIHRvdGFsX2J5X2NvdW50cnkgJT4lIA0KICB0b3Bfbih0b3RhbF9zYWxlcywgbiA9IC1uKSAlPiUgDQogIHB1bGwoY291bnRyeSkNCmBgYA0KDQotICAgTW9zdCBzYWxlcyBjb21lIGZyb20gZmV3IGNvdW50cmllcw0KLSAgIFRoZXJlIGFyZSBtYW55IGNvdW50cmllcyB3aXRoIHZlcnkgZmV3IHNhbGVzDQotICAgQ291bnRyaWVzIGxpa2UgKkNvdW50cnkgMjUqLCAqMjAqIG9yICo0MCogbWlnaHQgaGF2ZSBvdXRsaWVycy4gQmVmb3JlIHRyZWF0IHRoZW0gYXMNCiAgICBzdWNoLCB3ZSBzaG91bGQgaW52ZXN0aWdhdGUgaWYgdGhlc2UgdmFsdWVzIGFyZSBkdWUgdG8gaW5jcmVhc2UvZGVjcmVhc2UgaW4NCiAgICBpbnZlc3RtZW50cywgbWFya2V0aW5nLCBldGMuDQotICAgKkNvdW50cnkgNDAqIGhhcyBoaWdoIHZhcmlhYmlsaXR5LCBhcyB3ZWxsIGFzIG5lZ2F0aXZlIHNhbGVzIHZhbHVlcy4NCg0KYGBge3Igdml6LWJveHBsb3QtYnktY291bnRyeSwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9N30NCmdnX3RvcCA8LSBieV9jb3VudHJ5ICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSB0b3Bfbl8pICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoY291bnRyeSwgdmFsdWUpLCB5ID0gdmFsdWUsIGZpbGwgPSBjb3VudHJ5KSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bnVtYmVyKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSBwYWxldHRlKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gc3ByaW50ZigiVG9wICVkIGNvdW50cmllcyIsIG4pLCANCiAgICB4ID0gTlVMTCwgeSA9IE5VTEwNCiAgKQ0KDQpnZ19ib3R0b20gPC0gYnlfY291bnRyeSAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYm90dG9tX25fKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoY291bnRyeSwgdmFsdWUpLCB5ID0gdmFsdWUsIGZpbGwgPSBjb3VudHJ5KSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bnVtYmVyKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSBwYWxldHRlKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gc3ByaW50ZigiQm90dG9tICVkIGNvdW50cmllcyIsIG4pLCANCiAgICB4ID0gTlVMTCwgeSA9IE5VTEwNCiAgKQ0KDQpnZ190b3AgfCBnZ19ib3R0b20NCmBgYA0KDQpBbGwgbmVnYXRpdmUgc2FsZXMgYmVsb25nIHRvIGNsdXN0ZXIgMS4gVGhlcmUgYXJlIDE0IGNvdW50cmllcyB3aXRoIG5lZ2F0aXZlIHZhbHVlcyBidXQNCndpdGhvdXQgYSBkb3VidCB0aGUgbW9zdCBpbXBvcnRhbnQgb25lIGlzICpDb3VudHJ5IDQwKiB3aXRoIDUyIG1vbnRocyB3aXRoIG5lZ2F0aXZlIHNhbGVzLg0KDQpgYGB7ciB2aXotY2NvdW50cnksIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTgsIGVjaG89RkFMU0V9DQpieV9jb3VudHJ5ICU+JSANCiAgcGxvdF90aW1lX3Nlcmllcyh4ID0gZGF0ZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSBjb3VudHJ5KSArDQogIGZhY2V0X3dyYXAofiBjbHVzdGVyX2xhYmVsLCBuY29sID0gMywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCkluIGNhc2UgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHNlZSB0aGUgMTQgY291bnRyaWVzIHdpdGggbmVnYXRpdmUgc2FsZXMNCg0KYGBge3IgY291bnQtY291bnRyaWVzLXdpdGgtbmVnYXRpdmUtc2FsZXMsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCiMgQ29kZSB0byBjb3VudCBjbHVzdGVyLWNvdW50cmllcyB3aXRoIG5lZ2F0aXZlIHNhbGVzDQpieV9jb3VudHJ5ICU+JSANCiAgZmlsdGVyKHZhbHVlIDwgMCkgJT4lIA0KICBjb3VudChjbHVzdGVyLCBjb3VudHJ5LCBzb3J0ID0gVFJVRSkNCmBgYA0KDQpXZSBjb25maXJtIHRoYXQgdGhlIHR3byBiaWdnZXN0IGNvdW50cmllcyBhcmUgKkNvdW50cnkgMTkqIGFuZCAqQ291bnRyeSAxNyouIFRoZSBzYW1lDQpzaGFkZSBvZiBibHVlIGlzIG1haW50YWluZWQgdGhyb3VnaG91dCB0aGUgbWF0cml4LCBpbmRpY2F0aW5nIHRoYXQgbW9zdCBjb3VudHJpZXMgaGF2ZSB0aGUNCnNhbWUgbnVtYmVyIG9mIGJyYW5kcy4NCg0KYGBge3IgY291bnRyeS10cmVlbWFwLWRhdGF9DQp0cmVlX21hcF9jb3VudHJ5IDwtIGRhdGEgJT4lIA0KICBncm91cF9ieShjb3VudHJ5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBgTnVtYmVyIG9mIGJyYW5kc2AgPSBuX2Rpc3RpbmN0KGJyYW5kKSwNCiAgICBXZWlnaHQgPSBzdW0oc2FsZXNfMiwgbmEucm0gPSBUUlVFKQ0KICApICU+JQ0KICBtdXRhdGUoV2VpZ2h0ID0gV2VpZ2h0IC8gc3VtKFdlaWdodCkpICU+JSANCiAgcmVuYW1lKENvdW50cnkgPSBjb3VudHJ5KQ0KYGBgDQoNCmBgYHtyIGNvdW50cnktdHJlZW1hcC1wbG90fQ0KcG9pbnRGb3JtYXR0ZXIgPC0gSlMoImZ1bmN0aW9uKCl7DQogIHJldHVybiAnPGI+V2VpZ2h0PC9iPjogJyArIHRoaXMud190ZXh0ICsgJzxicj4nICsgJzxiPkJyYW5kczwvYj46ICcgKyANCiAgdGhpc1snTnVtYmVyIG9mIGJyYW5kcyddDQp9IikNCg0KdHJlZV9tYXBfY291bnRyeSAlPiUgDQogIG11dGF0ZSh3X3RleHQgPSBzY2FsZXM6OnBlcmNlbnQoV2VpZ2h0LCBhY2N1cmFjeSA9IDAuMDEpKSAlPiUNCiAgaGNoYXJ0KCJ0cmVlbWFwIiwgDQogICAgICAgICBoY2Flcyh4ID0gQ291bnRyeSwgdmFsdWUgPSBXZWlnaHQsIGNvbG9yID0gYE51bWJlciBvZiBicmFuZHNgKSwgDQogICAgICAgICBuYW1lID0gIldlaWdodCIpICU+JSANCiAgaGNfdG9vbHRpcChwb2ludEZvcm1hdHRlciA9IHBvaW50Rm9ybWF0dGVyKSAlPiUgDQogIGhjX2xlZ2VuZChhbGlnbiA9ICJyaWdodCIsIHZhbHVlRGVjaW1hbHMgPSAwKQ0KYGBgDQoNCiMjIEJyYW5kIEdyb3VwDQoNCkEgUGhhcm1hY2V1dGljYWwgcHJvZHVjdA0KDQpgYGB7ciB1bmlxdWUtYnJhbmQsIGVjaG89RkFMU0V9DQp1bmlxdWUoZGF0YSRicmFuZCkNCmBgYA0KDQpgYGB7ciBhZ2ctYnktYnJhbmR9DQpieV9icmFuZCA8LSBkYXRhICU+JSANCiAgZ3JvdXBfYnkoYnJhbmQsIGRhdGUpICU+JSANCiAgc3VtbWFyaXNlX2F0KHZhcnMoc2FsZXNfMTppbnZlc3RtZW50XzYpLCBzdW0sIG5hLnJtID0gVFJVRSkgJT4lDQogIHVuZ3JvdXAoKQ0KDQojIFNhdmUgdGhpcyBkYXRhc2V0IGZvciBsYXRlciB1c2UNCndyaXRlX3JkcyhieV9icmFuZCwgZmlsZSA9IGZpbGUucGF0aChwYXRoX2RhdGEsICJkYXRhX2xldmVsX2JyYW5kLnJkcyIpKQ0KDQoNCmJ5X2JyYW5kIDwtIGJ5X2JyYW5kICU+JSANCiAgZmlsdGVyKGRhdGUgPD0gbGFzdF90cmFpbikNCmBgYA0KDQpCcmFuZCAqT3RoZXJzKiBpcyB0aGUgbW9zdCBzaWduaWZpY2FudCBhdCB0aGUgc2FsZXMgbGV2ZWwgYW5kIHRoZSBvbmUgd2l0aCBncmVhdGVzdA0KZGlzcGVyc2lvbi4gVGhpcyBjYW4gYmUgZm9yIGFsbCB0aGUgYnJhbmRzIHRoYXQgaXQgZ3JvdXBzIChbc2VlIHJlLWNvZGluZw0KYnJhbmRzXSgjcmVjb2RlLWJyYW5kcykpLiBPbiB0aGUgb3RoZXIgaGFuZCwgKkJyYW5kIDQxKiwgKkJyYW5kIDMwKiBhbmQgKkJyYW5kIDM2KiBhcmUgdGhlDQpvbmVzIHdpdGggbGVzcyBkaXNwZXJzaW9uLg0KDQpgYGB7ciB2aXotbW9zdC1pbXBvcnRhbnQtYnJhbmR9DQpieV9icmFuZCAlPiUgDQogIGZpbHRlcihkYXRlIDw9IGxhc3RfdHJhaW4pICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoYnJhbmQsIHNhbGVzXzIpLCB5ID0gc2FsZXNfMiwgZmlsbCA9IGJyYW5kKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSBwYWxldHRlKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgY29sb3VyID0gTlVMTCwgZmlsbCA9IE5VTEwpDQpgYGANCg0KQmVsb3cgd2UgY2FuIHNlZSB0aGF0Og0KDQotICAgU2V2ZW4gb3V0IG9mIG5pbmUgYnJhbmRzIGFyZSBpbiBhbiB1cHRyZW5kLiAqQnJhbmQgR3JvdXAgNDEqIGFuZCAqT3RoZXJzKiBhcmUgdGhlIGJvdGgNCiAgICBpbiBhIGRvd250cmVuZCB3aXRoIHNpbWlsYXIgdHJlbmQgc3RydWN0dXJlLg0KLSAgICpCcmFuZCBHcm91cCAxNyogYW5kICpCcmFuZCBHcm91cCAyNCogcHJlc2VudCBhbiBleHBvbmVudGlhbCB0cmVuZC4gQm90aCBicmFuZHMgc3RhcnRzDQogICAgYmV0d2VlbiAyMDE1IGFuZCAyMDE2Lg0KLSAgICpCcmFuZCBHcm91cCAzMCosICpCcmFuZCBHcm91cCAzMSogYW5kICpCcmFuZCBHcm91cCA1MSwgNzMsIDkwKiBhcmUgaW4gYW4gdXB0cmVuZCB1cA0KICAgIHRvIHNvbWUgcG9pbnQgaW4gdGltZSBhbmQgdGhlbiBpdCBiZWNvbWVzIHRvIHJlbWFpbiBhbG1vc3QgZmxhdCBmb3IgdGhlIHJlc3Qgb2YgdGhlDQogICAgdGltZS4NCi0gICBCcmFuZCAqT3RoZXJzKiBoYXMgZGlwcyBpbiBhdWd1c3QsIGFzIGRvZXMgdG90YWwgc2FsZXMuDQoNCmBgYHtyIHZpei1icmFuZHMsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9DQpwbG90X3RpbWVfc2VyaWVzKGJ5X2JyYW5kLCB4ID0gZGF0ZSwgeSA9IHNhbGVzXzIsIGNvbG91ciA9IGJyYW5kKSArDQogIGZhY2V0X3dyYXAofiBicmFuZCwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnModGl0bGUgPSBOVUxMKQ0KYGBgDQoNCiMjIEFsbCBsZXZlbHMNCg0KVGhlIGZvcmVjYXN0IGlzIHJlcXVpcmVkIGF0IHRoZSBDbHVzdGVyIC0gQnJhbmQgbGV2ZWwuIFJlY2FsbCB0aGF0IGluaXRpYWxseSAxMTg0IFNLVSdzDQpoYXZlIGJlZW4gcHJvdmlkZWQgYW5kIGFmdGVyIHRoZSBbYWdncmVnYXRpb24gb2YgdGhlIHNlcmllc10oI3JlY29kZS1icmFuZHMpIHdlIGVuZCB1cA0Kd2l0aCA3NSBTS1Uncy4NCg0KSW4gdGhpcyBzZWN0aW9uIHdlIHdpbGwgYmUgYWJsZSB0byBhbnN3ZXIgcXVlc3Rpb24gc3VjaCBhczogRG8gdGhlIHNhbWUgYnJhbmQgZm9sbG93IHRoZQ0Kc2FtZSBwYXR0ZXJuIGRlc3BpdGUgdGhleSBkbyBub3QgYmVsb25nIHRvIHRoZSBzYW1lIGNsdXN0ZXI/DQoNCmBgYHtyIGFnZy1hdC1mb3JlY2F0LWxldmVsLCBlY2hvID0gVFJVRX0NCmFsbF9sZXZlbHMgPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlciwgYnJhbmQsIGRhdGUpICU+JQ0KICBzdW1tYXJpc2VfYXQodmFycyhzYWxlc18xOmludmVzdG1lbnRfNiksIHN1bSwgbmEucm0gPSBUUlVFKSAlPiUNCiAgdW5ncm91cCgpDQoNCiMgU2F2ZSB0aGlzIGRhdGFzZXQgZm9yIGxhdGVyIHVzZQ0Kd3JpdGVfcmRzKGFsbF9sZXZlbHMsIGZpbGUgPSBmaWxlLnBhdGgocGF0aF9kYXRhLCAiZGF0YV9sZXZlbF9za3UucmRzIikpDQoNCiMgS2VlcCBvbmx5IHdpdGggdHJhaW4gZGF0YSBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb25zDQphbGxfbGV2ZWxzIDwtIGFsbF9sZXZlbHMgJT4lDQogIGZpbHRlcihkYXRlIDw9IGxhc3RfdHJhaW4pDQpgYGANCg0KV2l0aCB0aGUgZm9sbG93aW5nIGNvZGUgd2UgcGxvdCBhbGwgdGhlIGJyYW5kcyBjb2xvcmVkIGJ5IGNsdXN0ZXIuIEhvd2V2ZXIsIHdlIHdpbGwgb25seQ0KcGxvdCB0aG9zZSBjYXNlcyB0aGF0IGhhdmUgcmVtYXJrYWJsZSBmZWF0dXJlcy4NCg0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NiwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KYWxsX2xldmVscyAlPiUgDQogIHBsb3RfdGltZV9zZXJpZXMoeCA9IGRhdGUsIHkgPSBzYWxlc18yLCBjb2xvdXIgPSBjbHVzdGVyKSArDQogIGZhY2V0X3dyYXAofiBicmFuZCwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmaXhlZCIpDQpgYGANCg0KU29tZSBicmFuZHMgYXJlIG1vcmUgcmVjZW50IHRoYW4gb3RoZXJzLiAqQnJhbmQgR3JvdXAgMTcqIGFuZCAqQnJhbmQgR3JvdXAgMjQqIGFyZQ0KZXhhbXBsZXMgb2YgcmVjZW50IGJyYW5kcy4gd2hlcmUgdGhleSBiZWdhbiB0byBiZSBtYXJrZXRlZCBmcm9tIHRoZSBiZWdpbm5pbmcgYW5kIGVuZCBvZg0KMjAxNSByZXNwZWN0aXZlbHkuDQoNCmBgYHtyIHZpei1icmFuZHMtMX0NCmFsbF9sZXZlbHMgJT4lIA0KICBmaWx0ZXIoYnJhbmQgJWluJSBjKCJCcmFuZCBHcm91cCAxNyIsICJCcmFuZCBHcm91cCAyNCIpKSAlPiUgDQogIHBsb3RfdGltZV9zZXJpZXMoeCA9IGRhdGUsIHkgPSBzYWxlc18yLCBjb2xvdXIgPSBjbHVzdGVyKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSBwYWxldHRlKSArDQogIGZhY2V0X3dyYXAofiBicmFuZCwgbmNvbCA9IDIsIHNjYWxlcyA9ICJmaXhlZCIpDQpgYGANCg0KSW4gdGhlIGNhc2Ugb2YgKkJyYW5kIEdyb3VwIDQxKiB3ZSBjYW4gc2VlIGEgbG90IG9mIHZhcmlhYmlsaXR5IHdpdGhpbiBjbHVzdGVycywgaGF2aW5nIGluDQpzb21lIGNsdXN0ZXJzIHZhbHVlcyBiZWxvdyAxMGsgYW5kIGluIG90aGVycyBhYm92ZSAyNWsuIE9uIHRoZSBvdGhlciBoYW5kLCBpdCBpcw0KaW50ZXJlc3RpbmcgdG8gc2VlIGhvdyB0aGUgc2FtZSBicmFuZCBiZWhhdmVzIGluIGEgc2ltaWxhciB3YXkgaW4gdmVyeSBjbHVzdGVyLiBUaGlzDQppbmRpY2F0ZSB1cyB0aGF0IHRoaXMgY291bGQgYmUgYSBnb29kIHdheSB0byB0cmFpbiBvdXIgbW9kZWxzLg0KDQpgYGB7ciB2aXotYnJhbmRzLTJ9DQphbGxfbGV2ZWxzICU+JSANCiAgZmlsdGVyKGJyYW5kICVpbiUgYygiQnJhbmQgR3JvdXAgNDEiLCAiQnJhbmQgR3JvdXAgOTYsIDk3IikpICU+JSANCiAgcGxvdF90aW1lX3Nlcmllcyh4ID0gZGF0ZSwgeSA9IHNhbGVzXzIsIGNvbG91ciA9IGNsdXN0ZXIpICsNCiAgZmFjZXRfd3JhcCh+IGJyYW5kLCBuY29sID0gMiwgc2NhbGVzID0gImZpeGVkIikNCmBgYA0KDQpXZSBjYW4gYWxzbyBhbmFseXplIHRoZSBjb250cmlidXRpb24gb2YgZWFjaCBwcm9kdWN0IGluIHRoZSBwb3J0Zm9saW8uIE1vcmUgdGhhbiA3NSUgb2YNCnRoZSBwcm9kdWN0cyBoYXZlIGEgd2VpZ2h0IGxlc3MgdGhhbiBvciBlcXVhbCB0byAyJSwgd2hpbGUgdGhlIG90aGVyIDI1JSBoYXZlIGEgd2VpZ2h0DQpiaWdnZXIgdGhhbiAyJS4gV2UgY2FuIGFsc28gc2VlIGhvdyBhcm91bmQgMTIlICg5IHByb2R1Y3RzKSBvZiB0aGUgcHJvZHVjdHMgaGF2ZSBhIHdlaWdodHMNCmdyZWF0ZXIgdGhhbiA0JS4gVGhpcyBzdWdnZXN0cyB0aGF0IHdlIHNob3VsZCBwdXQgbW9yZSBmb2N1cyBpbnRvIHNvbWUgcHJvZHVjdHMgdGhhbg0Kb3RoZXJzLg0KDQpgYGB7ciB2aXotZWNkZi1wcm9kdWN0c30NCmFsbF9sZXZlbHNfd2d0cyA8LSBhbGxfbGV2ZWxzICU+JSANCiAgZ3JvdXBfYnkoY2x1c3RlciwgYnJhbmQpICU+JSANCiAgc3VtbWFyaXNlKHdlaWdodCA9IHN1bShzYWxlc18yKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUod2VpZ2h0ID0gd2VpZ2h0IC8gc3VtKHdlaWdodCkpICU+JSANCiAgYXJyYW5nZShkZXNjKHdlaWdodCkpDQoNCmdncGxvdChhbGxfbGV2ZWxzX3dndHMsIGFlcyh3ZWlnaHQpKSArDQogIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjAyLCBsdHkgPSAyLCBjb2xvciA9ICJncmV5NTAiKSArDQogIGdlb21fcmVjdCgNCiAgICB4bWluID0gMCwgeG1heCA9IDAuMDIsIA0KICAgIHltaW4gPSAwLCB5bWF4ID0gSW5mLCANCiAgICBmaWxsID0gImxpZ2h0Z3JleSIsIA0KICAgIGFscGhhID0gMC4wMQ0KICApICsNCiAgYW5ub3RhdGUoDQogICAgZ2VvbSA9ICJsYWJlbCIsIHggPSAwLCB5ID0gMSwgDQogICAgbGFiZWwgPSAiUHJvZHVjdHMgd2l0aCBcbndlaWdodCA8PSAyJSIsIA0KICAgIGhqdXN0ID0gLTAuMSwgdmp1c3QgPSAxLCANCiAgICBzaXplID0gNA0KICApICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4wNCwgbHR5ID0gMiwgY29sb3IgPSAiZ3JleTUwIikgKw0KICBnZW9tX3JlY3QoDQogICAgeG1pbiA9IDAuMDQsIHhtYXggPSBJbmYsDQogICAgeW1pbiA9IDAsIHltYXggPSBJbmYsDQogICAgZmlsbCA9ICJsaWdodGdyZXkiLA0KICAgIGFscGhhID0gMC4wMQ0KICApICsNCiAgYW5ub3RhdGUoDQogICAgZ2VvbSA9ICJsYWJlbCIsIHggPSAwLjA1LCB5ID0gMC42LCANCiAgICBsYWJlbCA9ICJQcm9kdWN0cyB3aXRoIHdlaWdodCA+PSA0JSIsIA0KICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAxLCANCiAgICBzaXplID0gNA0KICApICsNCiAgc3RhdF9lY2RmKGdlb20gPSAic3RlcCIpICsNCiAgDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKw0KICBsYWJzKHggPSAiV2VpZ2h0IiwgeSA9ICJDdW11bGF0aXZlIGRlbnNpdHkiKQ0KYGBgDQoNCkZpbmFsbHksIHdlIGNhbiB2aXN1YWxpemUgYSB0cmVlIG1hcCBvZiB0aGUgd2VpZ2h0cyBvZiBlYWNoIHByb2R1Y3QuIE5vdGljZSBob3cgbW9zdA0KaW1wb3J0YW50IHByb2R1Y3RzIGJlbG9uZyB0byAqT3RoZXJzKiBhbmQgKkJyYW5kIEdyb3VwIDQxKi4gQmlnZ2VyIHNxdWFyZXMgYW5kIGRhcmtlcg0KY29sb3IgbWVhbnMgaGlnaGVyIGNvbnRyaWJ1dGlvbiB0byB0aGUgcG9ydGZvbGlvLg0KDQpgYGB7ciBhbGwtbGV2ZWxzLXRyZWVtYXAtcGxvdH0NCnBvaW50Rm9ybWF0dGVyIDwtIEpTKCJmdW5jdGlvbigpew0KICByZXR1cm4gJzxiPldlaWdodDwvYj46ICcgKyB0aGlzLndfdGV4dA0KfSIpDQoNCmFsbF9sZXZlbHNfd2d0cyAlPiUgDQogIHNsaWNlX21heChvcmRlcl9ieSA9IHdlaWdodCwgbiA9IDI1KSAlPiUgDQogIG11dGF0ZSgNCiAgICBpZCA9IHBhc3RlKGNsdXN0ZXIsIGJyYW5kLCBzZXAgPSAiPGJyPiIpLA0KICAgIHdfdGV4dCA9IHNjYWxlczo6cGVyY2VudCh3ZWlnaHQsIGFjY3VyYWN5ID0gMC4wMSkNCiAgKSAlPiUgDQogIGhjaGFydCgidHJlZW1hcCIsIA0KICAgICAgICAgaGNhZXMoeCA9IGlkLCB2YWx1ZSA9IHdlaWdodCwgY29sb3IgPSB3ZWlnaHQpLCANCiAgICAgICAgIG5hbWUgPSAiV2VpZ2h0IikgJT4lIA0KICBoY190b29sdGlwKHBvaW50Rm9ybWF0dGVyID0gcG9pbnRGb3JtYXR0ZXIpICU+JQ0KICBoY19sZWdlbmQoYWxpZ24gPSAicmlnaHQiLCB2YWx1ZURlY2ltYWxzID0gMCkNCmBgYA0KDQojIyBMYWdnZWQgc2FsZXMNCg0KTWFueSB0aW1lcyB0aGUgaW1wYWN0IG9mIHRoZSBpbW1lZGlhdGUgcGFzdCBzYWxlcyBpcyBub3QgcmVwcmVzZW50YXRpdmUgb2Ygd2hhdCB3aWxsIGNvbWUNCm5leHQuIEltYWdpbmUgdGhhdCB3ZSB3YW50IHRvIHByZWRpY3QgdGhlIHRlbXBlcmF0dXJlIHRoYXQgd2Ugd2lsbCBoYXZlIGluIGF1Z3VzdCBpbiBhbg0Kc3BlY2lmaWMgY291bnRyeS4gSXQgd291bGQgbWFrZSBzZW5zZSB0byBsb29rIGF0IHRoZSBwYXN0IEF1Z3VzdHMgYW5kIHNlZSB3aGF0IGlzIHRoZQ0KYXZlcmFnZSB0ZW1wZXJhdHVyZSByYXRoZXIgdGhhbiBsb29raW5nIGF0IHRoZSB0ZW1wZXJhdHVyZSBvZiBBcHJpbCBvciBKdW5lLg0KDQpPbiB0aGUgeC1heGlzIGlzIHJlcHJlc2VudGVkIHRoZSBsYWdnZWQgdmFsdWUgb2YgdGhlIHNhbGVzIGFuZCBpbiB0aGUgeS1heGlzIHRoZSByZWFsDQp2YWx1ZS4gQXMgY2xvc2VyIHRoZSBwb2ludHMgYXJlIHRvIHRoZSBkaWFnb25hbCBsaW5lIGJldHRlciB0aGUgY29ycmVsYXRpb24gaXQgaXMuIExhc3QNCnllYXIgc2FsZXMgKDEyIG1vbnRocykgc2VlbXMgYSBnb29kIHByZWRpY3RvciBvZiBjdXJyZW50IHNhbGVzLg0KDQpgYGB7ciBhdXgtZnVuY3Rpb24tY3JlYXRlLWxhZ3N9DQpnZXRfbGFncyA8LSBmdW5jdGlvbih2YXIsIG4gPSAzKXsNCiAgdmFyIDwtIGVucXVvKHZhcikNCiAgaW5kaWNlcyA8LSBzZXFfbGVuKG4pDQogIG1hcChpbmRpY2VzLCB+IHF1byhsYWcoISF2YXIsICEhLngpKSApICU+JSANCiAgICBzZXRfbmFtZXMoc3ByaW50ZigibGFnXyVzXyUwMmQiLCBybGFuZzo6cXVvX3RleHQodmFyKSwgaW5kaWNlcykpDQp9DQpgYGANCg0KYGBge3IgYWRkLXNhbGVzXzItbGFnc30NCnRvdGFsX3NhbGVzX2xhZ3MgPC0gdG90YWxfc2FsZXMgJT4lIA0KICB0cmFuc211dGUoc2FsZXNfMiwgDQogICAgYWNyb3NzKC5jb2xzID0gc2FsZXNfMiwgLmZucyA9IGdldF9sYWdzKHNhbGVzXzIsIDEyKSwgLm5hbWVzID0gIntmbn0iKQ0KICApDQoNCnBsb3RfZGF0YSA8LSB0b3RhbF9zYWxlc19sYWdzICU+JSANCiAgc2VsZWN0KA0KICAgIHNhbGVzXzIsIGxhZ19zYWxlc18yXzAzLCBsYWdfc2FsZXNfMl8wMywgbGFnX3NhbGVzXzJfMDksIA0KICAgIGxhZ19zYWxlc18yXzEyDQogICkgJT4lIA0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGNvbnRhaW5zKCJsYWdfIiksDQogICAgbmFtZXNfdG8gPSAibGFnX2lkIiwNCiAgICB2YWx1ZXNfdG8gPSAibGFnX3ZhbHVlIg0KICApDQpgYGANCg0KYGBge3Igdml6LWxhZ2dlZC1zYWxlcywgZmlnLmhlaWdodD0zLjUsIGZpZy53aWR0aD04LCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KcGxvdF9kYXRhICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbGFnX3ZhbHVlLCB5ID0gc2FsZXNfMikpICsNCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvdXIgPSAiYmxhY2siLCBmaWxsID0gIm9yYW5nZSIsIHNpemUgPSAzKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBzZSA9IEZBTFNFLCBjb2xvdXIgPSAiYmxhY2siLCBsdHkgPSAyKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIGZhY2V0X3dyYXAofiBsYWdfaWQsIG5jb2wgPSAzLCBzY2FsZXMgPSAiZml4ZWQiKQ0KYGBgDQoNCiMgSW52ZXN0bWVudHMNCg0KSW52ZXN0bWVudHMNCg0KIyMgT3ZlcmFsbCBpbnZlc3RtZW50cw0KDQpXaGF0IGlzIHRoZSBtb3N0IGltcG9ydGFudCBpbnZlc3RtZW50IHR5cGU/IEluIGFic29sdXRlIHRlcm1zLCB0aGUgbW9zdCBpbXBvcnRhbnQNCmludmVzdG1lbnQgYXJlICppbnZlc3RtZW50XzEqIGFuZCAqaW52ZXN0bWVudF8yKi4NCg0KYGBge3J9DQp0b3RhbF9zYWxlcyAlPiUgDQogIHNlbGVjdCgtc3RhcnRzX3dpdGgoInNhbGVzIikpICU+JSANCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBzdGFydHNfd2l0aCgiaW52ZXN0bWVudCIpLCANCiAgICBuYW1lc190byA9ICJpbnZlc3RtZW50IiwgDQogICAgdmFsdWVzX3RvID0gInZhbHVlIg0KICApICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gaW52ZXN0bWVudCwgeSA9IHZhbHVlKSkgKw0KICBnZW9tX2JveHBsb3Qoc2hvdy5sZWdlbmQgPSBGQUxTRSwgZmlsbCA9ICJncmF5IiwgYWxwaGEgPSAwLjcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKHN1ZmZpeCA9ICJLIiwgc2NhbGUgPSAxZS0zKQ0KICApICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiSW52ZXN0bWVudCBxdWFudGl0eSIpDQpgYGANCg0KIyMgU2FsZXMgdnMgSW52ZXN0bWVudHMNCg0KVG8gc2VlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gc2FsZXMgYW5kIGludmVzdG1lbnRzLCB3ZSBjYW4gcGxvdCBlYWNoIHRpbWUgc2VyaWVzDQphZ2FpbnN0IHRoZSBvdGhlcnMuIFRoZXNlIHBsb3RzIGNhbiBiZSBhcnJhbmdlZCBpbiBhIHNjYXR0ZXJwbG90IG1hdHJpeCwgdXNpbmcgdGhlDQpgR0dhbGx5YCBwYWNrYWdlLg0KDQpJbiB0aGlzIHBsb3QsIG1vc3RseSBuZWdhdGl2ZSByZWxhdGlvbnNoaXBzIHdpdGggKnNhbGVzXzIqIGFyZSByZXZlYWxlZCwgd2l0aCB0aGUNCnN0cm9uZ2VzdCByZWxhdGlvbnNoaXBzIGJlaW5nIHdpdGggKmludmVzdG1lbnRfMSogYW5kICppbnZlc3RtZW50XzUqIGFuZCB0aGUgd2Vha2VzdCB3aXRoDQoqaW52ZXN0bWVudF80Ki4NCg0KLSAgICpJbnZlc3RtZW50cyAxKiwgKjUqIGFuZCA2IGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoICpzYWxlc18yKg0KLSAgICpJbnZlc3RtZW50cyAxKiwgNWFuZCAqNiogYXJlIGhpZ2hseSBjb3JyZWxhdGVkIGJldHdlZW4gdGhlbS4gQmUgY2F1dGlvdXMgd2hlbg0KICAgIG1vZGVsaW5nIQ0KLSAgICpJbnZlc3RtZW50IDMqIGhhcyBhbiBvdXRsaWVyIG9uIHRoZSBsZWZ0IHRhaWwgb2YgdGhlIGRpc3RyaWJ1dGlvbi4NCi0gICAqSW52ZXN0bWVudCA0KiBkb2VzIG5vdCBoYXZlIGFueSBlZmZlY3Qgb3ZlciAqc2FsZXNfMioNCg0KYGBge3IgZ2dwYWlycy1pbnZlc3RtZW50cywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0NCnRvdGFsX3NhbGVzICU+JQ0KICBHR2FsbHk6OmdncGFpcnMoDQogICAgY29sdW1ucyA9IHNlcShmcm9tID0gMywgdG8gPSA5KSwNCiAgICAjIHRpdGxlID0gIlNhbGVzIHZzIEludmVzdG1lbnRzIiwNCiAgICBsb3dlciA9IGxpc3QoDQogICAgICBjb250aW51b3VzID0gR0dhbGx5Ojp3cmFwKA0KICAgICAgICAic21vb3RoIiwgbWV0aG9kID0gTUFTUzo6cmxtLCBzZSA9IEZBTFNFLCBzaGFwZSA9IDIxLCANCiAgICAgICAgY29sb3VyID0gImJsYWNrIiwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYSA9IDAuNiwgDQogICAgICAgIHNpemUgPSAyKQ0KICAgICkNCiAgKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihzdWZmaXggPSAiSyIsIHNjYWxlID0gMWUtMykNCiAgKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpDQpgYGANCg0KYGBge3IgbmV0LXNhbGVzLXZzLWludmVzdG1lbnRzLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD04LCBlY2hvPUZBTFNFfQ0KIyBwMSA8LSB0b3RhbF9zYWxlcyAlPiUgDQojICAgc2VsZWN0KGRhdGUsIHNhbGVzXzIsIGludmVzdG1lbnRfMSkgJT4lIA0KIyAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBzY2FsZSkgJT4lDQojICAgcGxvdF90aW1lX3Nlcmllcyh4ID0gZGF0ZSwgeSA9IHNhbGVzXzIsIHlfc2Vjb25kID0gaW52ZXN0bWVudF8xKSArDQojICAgbGFicyhzdWJ0aXRsZSA9ICJTYWxlcyB2cyBJbnZlc3RtZW50XzEiKQ0KIyANCiMgcDIgPC0gdG90YWxfc2FsZXMgJT4lIA0KIyAgIHNlbGVjdChkYXRlLCBzYWxlc18yLCBpbnZlc3RtZW50XzIpICU+JSANCiMgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpICU+JSANCiMgICBwbG90X3RpbWVfc2VyaWVzKHggPSBkYXRlLCB5ID0gc2FsZXNfMiwgeV9zZWNvbmQgPSBpbnZlc3RtZW50XzIpICsNCiMgICBsYWJzKHN1YnRpdGxlID0gIlNhbGVzIHZzIEludmVzdG1lbnRfMiIpDQojIA0KIyBwMyA8LSB0b3RhbF9zYWxlcyAlPiUgDQojICAgc2VsZWN0KGRhdGUsIHNhbGVzXzIsIGludmVzdG1lbnRfMykgJT4lIA0KIyAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBzY2FsZSkgJT4lIA0KIyAgIHBsb3RfdGltZV9zZXJpZXMoeCA9IGRhdGUsIHkgPSBzYWxlc18yLCB5X3NlY29uZCA9IGludmVzdG1lbnRfMykgKw0KIyAgIGxhYnMoc3VidGl0bGUgPSAiU2FsZXMgdnMgSW52ZXN0bWVudF8zIikNCiMgDQojIHA0IDwtIHRvdGFsX3NhbGVzICU+JSANCiMgICBzZWxlY3QoZGF0ZSwgc2FsZXNfMiwgaW52ZXN0bWVudF80KSAlPiUgDQojICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHNjYWxlKSAlPiUgDQojICAgcGxvdF90aW1lX3Nlcmllcyh4ID0gZGF0ZSwgeSA9IHNhbGVzXzIsIHlfc2Vjb25kID0gaW52ZXN0bWVudF80KSArDQojICAgbGFicyhzdWJ0aXRsZSA9ICJTYWxlcyB2cyBJbnZlc3RtZW50XzQiKQ0KIyANCiMgcDUgPC0gdG90YWxfc2FsZXMgJT4lIA0KIyAgIHNlbGVjdChkYXRlLCBzYWxlc18yLCBpbnZlc3RtZW50XzUpICU+JSANCiMgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpICU+JSANCiMgICBwbG90X3RpbWVfc2VyaWVzKHggPSBkYXRlLCB5ID0gc2FsZXNfMiwgeV9zZWNvbmQgPSBpbnZlc3RtZW50XzUpICsNCiMgICBsYWJzKHN1YnRpdGxlID0gIlNhbGVzIHZzIEludmVzdG1lbnRfNSIpDQojIA0KIyBwNiA8LSB0b3RhbF9zYWxlcyAlPiUgDQojICAgc2VsZWN0KGRhdGUsIHNhbGVzXzIsIGludmVzdG1lbnRfNikgJT4lIA0KIyAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBzY2FsZSkgJT4lIA0KIyAgIHBsb3RfdGltZV9zZXJpZXMoeCA9IGRhdGUsIHkgPSBzYWxlc18yLCB5X3NlY29uZCA9IGludmVzdG1lbnRfNikgKw0KIyAgIGxhYnMoc3VidGl0bGUgPSAiU2FsZXMgdnMgSW52ZXN0bWVudF82IikNCg0KIyAocDEgLyBwMiAvIHAzKSB8ICggcDQgLyBwNSAvIHA2KQ0KYGBgDQoNClRocmVlIG91dCBvZiBzaXggaW52ZXN0bWVudHMgaGF2ZSBhIG5lZ2F0aXZlIHRyZW5kLCB0aGVyZWZvcmUsIGl0IGluZGljYXRlcyB0aGF0IG1vcmUgYW5kDQptb3JlIGhhcyBiZWVuIGludmVzdGVkLiBSZWNhbGwgdGhhdCBpbnZlc3RtZW50cyBhcmUgbmVnYXRpdmUgYW5kIGxvd2VyIGludmVzdG1lbnRzIG1lYW5zDQptb3JlIGludmVzdGluZy4NCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9DQp0b3RhbF9zYWxlcyAlPiUgDQogIHNlbGVjdChkYXRlLCBzYWxlc18yLCBpbnZlc3RtZW50XzEsIGludmVzdG1lbnRfNSwgaW52ZXN0bWVudF82KSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBzY2FsZSkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJpbnZlc3RtZW50IikpICU+JSANCiAgcGxvdF90aW1lX3Nlcmllcyh4ID0gZGF0ZSwgeSA9IHNhbGVzXzIsIHlfc2Vjb25kID0gdmFsdWUpICsNCiAgZmFjZXRfd3JhcCh+IG5hbWUsIHNjYWxlcyA9ICJmaXhlZCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCkNCmBgYA0KDQpPbiB0aGUgb3RoZXIgaGFuZCwgdGhlcmUgaXMgYW5vdGhlciBncm91cCBvZiBpbnZlc3RtZW50cyB0aGF0IGFyZSBzdGF0aW9uYXJ5LCB0aGF0IGlzLA0KdGhleSBhcmUgbW92aW5nIGFyb3VuZCB0aGVpciBtZWFuLiBJbiBhZGRpdGlvbiwgKmludmVzdG1lbnRfMiogaGFzIGFubnVhbCBzZWFzb25hbGl0eSwNCndpdGggc3Bpa2VzIGluIGF1Z3VzdCBhbmQgU2VwdGVtYmVyIGFuZCB2YWxsZXlzIGluIERlY2VtYmVyLg0KDQpJbiBKYW51YXJ5IG9mIDIwMTYgdGhlcmUgaXMgYW4gb3V0bGllciBpbiB0aGUgKmludmVzdG1lbnRfMyouDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zfQ0KdG90YWxfc2FsZXMgJT4lIA0KICBzZWxlY3QoZGF0ZSwgc2FsZXNfMiwgaW52ZXN0bWVudF8yLCBpbnZlc3RtZW50XzMsIGludmVzdG1lbnRfNCkgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiaW52ZXN0bWVudCIpKSAlPiUgDQogIHBsb3RfdGltZV9zZXJpZXMoeCA9IGRhdGUsIHkgPSBzYWxlc18yLCB5X3NlY29uZCA9IHZhbHVlKSArDQogIGZhY2V0X3dyYXAofiBuYW1lLCBzY2FsZXMgPSAiZml4ZWQiKSArDQogIHNjYWxlX3lfY29udGludW91cygpDQpgYGANCg0KIyMgTGFnZ2VkIEludmVzdG1lbnRzDQoNClNvbWV0aW1lcywgdGhlIGltcGFjdCBvZiBhIHByZWRpY3RvciB0aGF0IGlzIGluY2x1ZGVkIGluIGEgcmVncmVzc2lvbiBtb2RlbCB3aWxsIG5vdCBiZQ0Kc2ltcGxlIGFuZCBpbW1lZGlhdGUuIEZvciBleGFtcGxlLCBhbiBhZHZlcnRpc2luZyBjYW1wYWlnbiBtYXkgaW1wYWN0IHNhbGVzIGZvciBzb21lIHRpbWUNCmJleW9uZCB0aGUgZW5kIG9mIHRoZSBjYW1wYWlnbiwgYW5kIHNhbGVzIGluIG9uZSBtb250aCB3aWxsIGRlcGVuZCBvbiB0aGUgYWR2ZXJ0aXNpbmcNCmV4cGVuZGl0dXJlIGluIGVhY2ggb2YgdGhlIHBhc3QgZmV3IG1vbnRocy4NCg0KYGBge3IgY3JlYXRlLWxhZ3MtaW52ZXN0bWVudDEsIGVjaG89RkFMU0V9DQojIGxpYnJhcnkodGltZXRrKQ0KIyANCiMgbGFnX2ludmVzdG1lbnRfMSA8LSB0b3RhbF9zYWxlcyAlPiUNCiMgICBzZWxlY3QoZGF0ZSwgc2FsZXNfMiwgaW52ZXN0bWVudF81KSAlPiUgDQojICAgdGtfdGJsKHJlbmFtZV9pbmRleCA9ICJkYXRlIikgJT4lDQojICAgdGtfYXVnbWVudF9sYWdzKA0KIyAgICAgLnZhbHVlID0gaW52ZXN0bWVudF81LA0KIyAgICAgLm5hbWVzID0gImF1dG8iLA0KIyAgICAgLmxhZ3MgPSBzZXEoMSwgMTIpDQojICAgKSAlPiUNCiMgICBwaXZvdF9sb25nZXIoDQojICAgICBjb2xzID0gY29udGFpbnMoImludmVzdG1lbnRfNV9sYWciKSwNCiMgICAgIG5hbWVzX3RvID0gImxhZ19pZCIsDQojICAgICB2YWx1ZXNfdG8gPSAibGFnX3ZhbHVlIg0KIyAgICkNCmBgYA0KDQpgYGB7ciBwbG90LWxhZ3MtaW52ZXN0bWVudDEsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTgsIGVjaG89RkFMU0V9DQojIGxpYnJhcnkoZ2dwdWJyKSAjIE5lZWRlZCBmb3IgZ2dwbG90IHN0YXRfY29yKCkNCiMgDQojIGxhZ19pbnZlc3RtZW50XzEgJT4lDQojICAgdGltZXRrOjpwbG90X3RpbWVfc2VyaWVzKA0KIyAgICAgLmRhdGVfdmFyID0gc2FsZXNfMiwNCiMgICAgIC52YWx1ZSA9IGxhZ192YWx1ZSwNCiMgICAgIC5mYWNldF92YXJzID0gbGFnX2lkLA0KIyAgICAgLmZhY2V0X25jb2wgPSAzLA0KIyAgICAgLmludGVyYWN0aXZlID0gRkFMU0UsDQojICAgICAuc21vb3RoID0gRkFMU0UsDQojICAgICAubGluZV9hbHBoYSA9IDAsDQojICAgICAubGVnZW5kX3Nob3cgPSBGQUxTRSwNCiMgICAgIC5mYWNldF9zY2FsZXMgPSAiZml4ZWQiDQojICAgKSArDQojICAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gbGFnX2lkKSkgKw0KIyAgIGdlb21fYWJsaW5lKGNvbG91ciA9ICJncmF5IiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KIyAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsNCiMgICBzdGF0X2NvcihsYWJlbC55Lm5wYyA9IDAuMSkgKw0KIyAgICMgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnkgPSAtMTApICsNCiMgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkNCmBgYA0K